package com.xiezc;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import com.xiezc.model.Device;
import com.xiezc.model.PTypeEnum;
import com.xiezc.model.Packet;
import lombok.Data;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;

/**
 * @author wb-xzc291800
 * @date 2018/09/05 13:50
 */
@Slf4j
public class SendService {

    public static AtomicBoolean heartBeat = new AtomicBoolean(false);

    private SendService(DatagramChannel channel) {
        super();
        this.channel = channel;
    }

    static SendService sendService;

    private BlockingQueue<SendObj> sendBuf = new LinkedBlockingQueue<>();

    final DatagramChannel channel;

    @Synchronized
    public static SendService single(DatagramChannel channel) {
        if (sendService == null) {
            sendService = new SendService(channel);
        }
        log.info("SendService 发送包服务初始化完成.....");
        return sendService;
    }

    public boolean addBuf(Packet data, Device device) {
        SendObj bufferObj = disassemblyPacket(data, device);
        return sendBuf.add(bufferObj);
    }

    public boolean addBuf(SendObj data) {
        return sendBuf.add(data);
    }

    public boolean addBuf(List<SendObj> data) {
        return sendBuf.addAll(data);
    }

    public void start() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    SendObj take = sendBuf.poll(1000, TimeUnit.MILLISECONDS);
                    if (take == null) {
                        heartBeat.compareAndSet(false, true);
                        continue;
                    }
                    channel.send(take.getByteBuffer(), take.getInetSocketAddress());

                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }, "send_bufferObj");
        thread.setDaemon(true);
        thread.start();
    }

    /**
     * @param packet
     * @throws IOException
     */
    private SendObj disassemblyPacket(Packet packet, Device device) {
        byte[] content = packet.getContent();
        int contLen = 0;
        if (content != null) {
            contLen = packet.getContent().length;
        }
        ByteBuffer byteBuffer = ByteBuffer.allocate(contLen + Xutil.headLen);
        //1. 包类型
        PTypeEnum ptype = packet.getPtype();
        byteBuffer.put(ptype.getVal());
        //2. 设备的ID
        byteBuffer.putLong(packet.getDeviceId());
        //3. 令牌
        byteBuffer.putLong(packet.getToken());
        //4. 消息的ID
        byteBuffer.putLong(packet.getMsgId());
        //5. 包的序号
        byteBuffer.putLong(packet.getIndex());
        //6. 总包数
        byteBuffer.putLong(packet.getLen());
        //7. 包的md5
        byteBuffer.put(packet.getPackMd5());
        //8. 包的内容
        if (packet.getContent() != null) {
            byteBuffer.put(packet.getContent());
        }
        byteBuffer.flip();

        SendObj bufferObj = new SendObj();
        bufferObj.setByteBuffer(byteBuffer);
        bufferObj.setInetSocketAddress(device.getAddress());
        return bufferObj;
    }
}

/**
 * @author wb-xzc291800
 * @date 2018/09/05 14:07
 */
@Data
class SendObj {

    ByteBuffer byteBuffer;

    InetSocketAddress inetSocketAddress;
}
